package com.huterox.todoscheduler.core.execute.impl;

import com.huterox.todoscheduler.core.enumType.TodoItemElementType;
import com.huterox.todoscheduler.core.enumType.TodoItemStateType;
import com.huterox.todoscheduler.core.enumType.TodoListElementType;
import com.huterox.todoscheduler.core.enumType.TodoListStateType;
import com.huterox.todoscheduler.core.execute.ExecuteCore;
import com.huterox.todoscheduler.core.execute.TodoListFactory;
import com.huterox.todoscheduler.core.execute.proxy.TodoItemExBean;
import com.huterox.todoscheduler.core.execute.proxy.TodoListExBean;
import com.huterox.todoscheduler.core.global.TodoListFailedList;
import com.huterox.todoscheduler.core.wapper.ItemStateWrapper;
import com.huterox.todoscheduler.core.wapper.ListStateWrapper;
import com.huterox.todoscheduler.handler.*;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;

/**
 * 负责执行清单的执行类，通过TodoListFactory来创建
 * ToDoListEx类，之后，运行这个ToDoListEx类
 * */
public class DefaultExecuteCore implements ExecuteCore, Serializable {

    private TodoListExBean todoListExBean;
    private boolean running = true;

    @Override
    public void execute(String ListName) {
        //1. 先拿到可执行清单对象
        todoListExBean = TodoListFactory.getInstance(ListName);
        //2. 查看返回的结果
        if(todoListExBean==null){
            //说明创建就失败了，这个失败是清单对象都没有起来
            this.running = false;
        }else {
            if(todoListExBean.getTodoListStateType()== TodoListStateType.CreatFailed){
                //创建失败了
                if(todoListExBean.getTodoListElementType()== TodoListElementType.NothingConsistency
                    || todoListExBean.getTodoListElementType()== TodoListElementType.WeakConsistency
                ){
                    //在创建阶段，只要你不是强一致性，那么我就不管你，如果创建都失败了
                    System.err.println("任务清单创建失败，取消执行");
                }else if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency){
                    //强一致，这个时候，直接进入失败队列,这个时候也是创建失败，但是这个失败是指
                    //清单项目创建的时候有问题，清单对象起来了
                    TodoListFailedList.addFailedWithSerializable(todoListExBean);
                    this.running = false;
                }
            }
        }
    }

    public TodoListExBean getTodoListExBean() {
        return todoListExBean;
    }

    public void setTodoListExBean(TodoListExBean todoListExBean) {
        this.todoListExBean = todoListExBean;
    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

    @Override
    public String getClsId() {
        return todoListExBean.getClsId();
    }

    @Override
    public void run() {

        if(!this.running){
            System.err.println("执行失败，停止执行该任务清单");
            return;
        }

        todoListExBean.setExTimes(todoListExBean.getExTimes()+1);
        todoListExBean.setTodoListStateType(TodoListStateType.Running);
        //在这里完成方法任务清单项的执行
        //同时在这里完成状态的持久化处理，方便恢复状态
        Map<Integer, TodoItemExBean> sortedMap = todoListExBean.getSortedMap();

        //开始遍历执行清单项
        for(Map.Entry<Integer, TodoItemExBean> entry:sortedMap.entrySet()){
            Integer key = entry.getKey();
            TodoItemExBean entryValue = entry.getValue();
            entryValue.setTodoItemStateType(TodoItemStateType.Running);
            //这里开始按照生命周期执行代码
            try {
                if (entryValue.getTodoItemBeforeRunningHandler()!=null)
                {
                    //执行第一个运行时，运行前的代码
                    TodoItemBeforeRunningHandler todoItemBeforeRunningHandler = entryValue.
                            getTodoItemBeforeRunningHandler();
                    boolean concierge = todoItemBeforeRunningHandler.concierge(
                            entryValue.getStateWrapper(),
                            todoListExBean.getStateWrapper()
                    );
                    if(!concierge){

                        //没有满足通过条件，需要跳过或者终止
                        if(entryValue.getTodoItemElementType()== TodoItemElementType.CONTINUTEITEM){
                            System.err.println("任务清单："+todoListExBean.getTodoListName()
                                    +"-Cid:" + todoListExBean.getClsId()+"第"+entryValue.getOrder()+
                                    "方法："+entryValue.getWrapperMethod().getName()+"未通过运行时执行前Handler"
                                    +"正在前往执行下一个任务项"
                                    );
                        }else {
                            //查看当前任务清单类型，如果是那种强一致性的，那就加入失败队列，等待重启
                            if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency) {
                                //强一致，这个时候，直接进入失败队列
                                entryValue.setTodoItemStateType(TodoItemStateType.Again);
                                TodoListFailedList.addFailedWithSerializable(todoListExBean);
                            }else if(
                                todoListExBean.getTodoListElementType()==TodoListElementType.WeakConsistency
                            ){
                                entryValue.setTodoItemStateType(TodoItemStateType.Repairing);
                            }
                            return;
                        }
                        entryValue.setTodoItemStateType(TodoItemStateType.Repairing);
                        //这个时候由于没有满足条件，那么这个时候要执行对应的恢复函数
                        todoItemBeforeRunningHandler.repair(
                                entryValue.getStateWrapper(),
                                todoListExBean.getStateWrapper()
                        );
                    }
                }

                //执行运行时刻代码
                Method wrapperMethod = entryValue.getWrapperMethod();
                wrapperMethod.setAccessible(true);
                Parameter[] parameters = wrapperMethod.getParameters();

                // 构造参数数组
                Object[] argsArray = new Object[parameters.length];
                for (int i = 0; i < parameters.length; i++) {
                    Parameter parameter = parameters[i];
                    if (parameter.getType() == ListStateWrapper.class) {
                        // 设置特定参数的值
                        argsArray[i] = todoListExBean.getStateWrapper();
                    }else if(parameter.getType() == ItemStateWrapper.class){
                        argsArray[i] = entryValue.getStateWrapper();
                    }
                }
                // 执行方法
                Object result = wrapperMethod.invoke(entryValue, argsArray);

                //执行后置处理,这个执行流程和前置是一样的
                if (entryValue.getTodoItemAfterRunningHandler()!=null){
                    TodoItemAfterRunningHandler todoItemAfterRunningHandler = entryValue.getTodoItemAfterRunningHandler();
                    boolean concierge = todoItemAfterRunningHandler.concierge(
                            entryValue.getStateWrapper(),
                            todoListExBean.getStateWrapper()
                    );
                    if(!concierge){
                        entryValue.setTodoItemStateType(TodoItemStateType.Repairing);
                        if(entryValue.getTodoItemElementType()== TodoItemElementType.CONTINUTEITEM){
                            System.err.println("任务清单："+todoListExBean.getTodoListName()
                                    +"-Cid:" + todoListExBean.getClsId()+"第"+entryValue.getOrder()+
                                    "方法："+entryValue.getWrapperMethod().getName()+"未通过运行时执行前Handler"
                                    +"正在前往执行下一个任务项"
                            );
                        }else {
                            if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency) {
                                //强一致，这个时候，直接进入失败队列
                                entryValue.setTodoItemStateType(TodoItemStateType.Again);
                                TodoListFailedList.addFailedWithSerializable(todoListExBean);
                            }else if(
                                    todoListExBean.getTodoListElementType()==TodoListElementType.WeakConsistency
                            ){
                                entryValue.setTodoItemStateType(TodoItemStateType.Repairing);
                            }
                            return;
                        }
                        //这个时候由于没有满足条件，那么这个时候要执行对应的恢复函数
                        todoItemAfterRunningHandler.repair(
                                entryValue.getStateWrapper(),
                                todoListExBean.getStateWrapper()
                        );
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                //对错误进行处理
                entryValue.setTodoItemStateType(TodoItemStateType.Error);
                if(entryValue.getTodoItemErrorHandler()!=null){
                    try {
                        TodoItemErrorHandler todoItemErrorHandler = entryValue.getTodoItemErrorHandler();
                        todoItemErrorHandler.concierge(
                                entryValue.getStateWrapper(),
                                todoListExBean.getStateWrapper()
                        );
                    }catch (Exception e1){
                        e1.printStackTrace();
                        //如果这个都执行失败了，那真的没救了
                        //加入失败列表看看了，只能，如果是一定要执行的话
                        if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency){
                            TodoListFailedList.addFailedWithSerializable(todoListExBean);
                        }else {
                            System.err.println("任务强制终止");
                        }
                        return;
                    }
                }
            }
            //此时这个任务清单的小项目才算执行正常
            entryValue.setTodoItemStateType(TodoItemStateType.Fine);
        }
        //清单项目是执行完毕了，那么接下来是这个清单的后置处理部分
        if(todoListExBean.getTodoListAfterHandler()!=null) {
            TodoListAfterHandler todoListAfterHandler = todoListExBean.getTodoListAfterHandler();
            try {
                boolean concierge = todoListAfterHandler.concierge(todoListExBean.getStateWrapper());
                if(!concierge) {

                    todoListExBean.setTodoListStateType(TodoListStateType.Repairing);
                    //这个时候由于没有满足条件，那么这个时候要执行对应的恢复函数
                    todoListAfterHandler.repair(
                            todoListExBean.getStateWrapper()
                    );
                }
            } catch (Exception e) {
                e.printStackTrace();
                todoListExBean.setTodoListStateType(TodoListStateType.Error);
                //对错误进行处理
                if(todoListExBean.getTodoListErrorHandler()!=null){
                    try {
                        TodoListErrorHandler todoListErrorHandler = todoListExBean.getTodoListErrorHandler();
                        todoListErrorHandler.concierge(
                                todoListExBean.getStateWrapper()
                        );
                    }catch (Exception e1){
                        e1.printStackTrace();
                        if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency){
                            todoListExBean.setTodoListStateType(TodoListStateType.Error);
                            TodoListFailedList.addFailedWithSerializable(todoListExBean);
                        }else {
                            System.err.println("任务强制终止");
                        }
                    }
                }
            }
        }

        todoListExBean.setTodoListStateType(TodoListStateType.Fine);
    }

    /**
     * 这个是当服务器宕机之后，或者出现奇奇怪怪的东西的时候
     * 我们进行一个修复操作，这里的修复主要是通过这个这个
     * 判断这个todoListExBean的一个状态来完成的，我们真实执行操作的时候
     * 是这样的，TaskWrapper-->封装Execute--->在Execute里面对todoListExBean进行操作
     * Execute 负责管理todoListExBean的状态，同时还有这个拼接执行方法，其实就是个代理
     *
     * */
    @Override
    public void repair() {
        //这里的话明确一点，那就是在我们的任务清单有好几种状态，一个是没有状态，还没有执行完毕
        //还有一个是运行状态，对应意外宕机，我们唯一能够做的就是执行修复方法。此时在调用这个方法的
        //时候只有两种情况：1. 任务执行完毕，还没有来得及移除任务队列，2. 在执行复原状态
        //所以现在我们这边主要就是对这个情况进行操作，因为完整地进行跟进复原确实有点难受，先简单这样
        //进行实现，后面再进行优化。这里的话，其实按照道理，我们都要做一套日志系统的，但是这里没有只是简单
        //输出，所以的话，后面可以考虑植入更多的组件，当然更主要的原因是，一开始没有考虑那么多，只是做一个简单
        //的dome出来先看看，后面再把这个部分给拆了，就可以在这里插入更多组件了

        TodoListStateType todoListStateType = todoListExBean.getTodoListStateType();
        if(todoListStateType!=null){
            if(todoListExBean.getTodoListStateType()==TodoListStateType.Repairing){
                //重新继续执行
                if(todoListExBean.getTodoListAfterHandler()!=null){
                    TodoListAfterHandler todoListAfterHandler = todoListExBean.getTodoListAfterHandler();
                    try {
                        todoListAfterHandler.repair(todoListExBean.getStateWrapper());
                    } catch (Exception e) {
                        e.printStackTrace();
                        //这个要是继续执行失败的话，调用它的失败处理器，重复先前的操作
                        if(todoListExBean.getTodoListErrorHandler()!=null){
                            try {
                                TodoListErrorHandler todoListErrorHandler = todoListExBean.getTodoListErrorHandler();
                                todoListErrorHandler.concierge(
                                        todoListExBean.getStateWrapper()
                                );
                            }catch (Exception e1){
                                e1.printStackTrace();
                                if(todoListExBean.getTodoListElementType()==TodoListElementType.StrongConsistency){
                                    todoListExBean.setTodoListStateType(TodoListStateType.Error);
                                    TodoListFailedList.addFailedWithSerializable(todoListExBean);
                                }else {
                                    System.err.println("任务强制终止");
                                }
                            }
                        }

                        //占个坑位，后面做日志组件，配合数据库，其实后面在这个上面做一套Web都是可以的
                        //不过实现Web的话，可能考虑内嵌一个打包好的软件来做了，非要我做，那我就自定义日志
                        //格式，然后用Python快速做一个可视化web应用，解析日志格式，然后显示即可，Python写起来
                        //比较快，主要还是，你也不想，看日志还要打开tomcat吧，并且展示的需求不复杂，对于这种日志查看
                        //还要vue+SB那实在是太SB了，即便是Vue+flask我都嫌弃麻烦，一个Python Gradio 都能搞定的事情
                        //还要老一套太慢了。

                    }
                }
            }else if(todoListExBean.getTodoListStateType()==TodoListStateType.Running){
                //此时还在运行，那么就要看看有哪些方法了
                Map<Integer, TodoItemExBean> sortedMap = todoListExBean.getSortedMap();

                //开始遍历执行清单项
                for(Map.Entry<Integer, TodoItemExBean> entry:sortedMap.entrySet()){
                    //注意我们这里只进行修复，万一重复执行了，扣了两次钱咋办
                    TodoItemExBean value = entry.getValue();
                    if(value.getTodoItemStateType()!=null){
                        TodoItemStateType todoItemStateType = value.getTodoItemStateType();
                        if(todoItemStateType==TodoItemStateType.Repairing){
                            //执行修复,这里的话，我们执行的是方法的后置处理的修复方法
                            if(value.getTodoItemAfterRunningHandler()!=null){
                                TodoItemAfterRunningHandler todoItemAfterRunningHandler = value.getTodoItemAfterRunningHandler();
                                try {
                                    todoItemAfterRunningHandler.repair(
                                            value.getStateWrapper(),todoListExBean.getStateWrapper()
                                    );
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    //同样的，如果这里G了，那么一样大哥也就救不了，Sorry
                                }

                            }

                        }
                    }

                }
            }
        }

    }
}
